/**
 * @file    DataModels.h
 * @brief   Include classes and interface for convenience data-wrapping and rendering.
 *
 ****************************************************************************
 * \defgroup DataModels Core-DataModels
 *
 *
 *
 * PROBLEMS:
 *  - Variant DATETIME interpretation, should be possible to customize someway
 *  - const!!  methodExtractor f* is always const, almost always ok but..
 *
 *
 *\code
// create data adapter for local objects' list
DataAdapterListT<Bundle>* dataAdapter = new DataAdapterListT<Bundle>(this->bundles);
// collector holding all available fields could be extracted
DataFieldCollector<Bundle>* fields = new DataFieldCollector<Bundle>();
// inline add (using DataFieldWrapperT)
fields->add<const std::string&, Variant>(&Bundle::getName, "Name", 0);
fields->add<const char*, Variant>(&Bundle::getClassName, "Type", 1);
fields->add<const char*,Variant>(&Bundle::getBundleStateAsString, "State", 2);
// extract a new URI (which is ISerializable) using copy-constructor (PROXY is return-type itself)
fields->add<const URI&,URI>(&Bundle::getURI, "URI", 4);
// extract a new ISerializable object, generated by PROXY_TYPE (InterfacesProvider) accessed by 1st function pointer
// and apply 2nd function pointer to generate the object, ALLOCATOR_TYPE is void (so object will be acquired, not copied!)
DataFieldSubWrapperT<Bundle, const InterfacesProvider*, List*, void>* dfwInterfacesList;
dfwInterfacesList = new DataFieldSubWrapperT<Bundle, const InterfacesProvider*, List*, void>(&Bundle::bundleInterfaces, &InterfacesProvider::toList, "Interfaces", 3);
fields->add(dfwInterfacesList);
// some more optional fields, not included in default list:
fields->add<const std::string&,Variant>(&Bundle::getEntityID, "EntityID", 5, false);
fields->add<const Permission&,Permission>(&Bundle::getPermission, "Permission", 6, false);
fields->add<Bundle::BUNDLE_STATE,Variant>(&Bundle::getBundleState, "State[int]", 2, false); // duplicate but different type
// explicit add
DataFieldSubWrapperT<Bundle, const InterfacesProvider*, std::string, Variant>* dfwInterfacesStr;
dfwInterfacesStr = new DataFieldSubWrapperT<Bundle, const InterfacesProvider*, std::string, Variant>(&Bundle::bundleInterfaces, &InterfacesProvider::toString, "Interfaces[Str]", 1);
fields->add(dfwInterfacesStr);

DataFieldExtractor<Bundle>* dExt = new DataFieldExtractor<Bundle>(dataAdapter, fields);

MethodList* mmListTMP = Methods.create<MethodList>( "prova", "", Permission(Permission::RX) );
mmListTMP->setDataAdapter(dataAdapter); // acquire obj ownership
mmListTMP->setDataFields(fields); // acquire obj ownership
mmListTMP->setDataFieldExtractor(dExt); // acquire obj ownership
 *\endcode
 *
 *
 ****************************************************************************
 * @version 0.8.384 $Id: DataModels.h 2828 2010-08-02 11:16:31Z alex $
 * @author  Alessandro Polo
 ****************************************************************************/
/* Copyright (c) 2007-2010, WOSH - Wide Open Smart Home 
 * by Alessandro Polo - OpenSmartHome.com
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the OpenSmartHome.com WOSH nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY Alessandro Polo ''AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL Alessandro Polo BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR MethodRequestS;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ****************************************************************************/


#ifndef __WOSH_Core_DataModels_H__
 #define __WOSH_Core_DataModels_H__

 #include <woshDefs.h>
 #include <core/Serialization.h>
 #include <core/Variant.h>
 #include <core/List.h>
 #include <core/Table.h>
 #include <core/Object.h>

#include <vector>
#include <algorithm>


namespace wosh {

////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////

///----------------------------------------------------------------------------------------------------------------------
///----------------------------------------------------------------------------------------------------------------------
enum FIELD_SORT_ORDER {
	FIELD_SORT_UNORDERED	= 0x00,
	FIELD_SORT_ASCENDING	= 0x01,
	FIELD_SORT_DESCENDING	= 0x02
 };

/**
 * @class   wosh::DataFieldSettings
 * @brief   Represent a generic field.
 ****************************************************************************
 *
 * @ingroup DataModels
 ****************************************************************************
 * @version 0.8.384 $Id $
 * @author  Alessandro Polo
 ****************************************************************************/
struct DataFieldSettings {
	int uid;
	ISerializable* header;
	int index;
	bool visible;
	short sort_mode;

	DataFieldSettings()
		: uid(0), header(NULL), index(0), visible(true), sort_mode(FIELD_SORT_UNORDERED) { }
	~DataFieldSettings() {
		setHeader(NULL);
	 }

	void setHeader( ISerializable* new_header ) {
		if ( this->header != NULL ) delete this->header;
		this->header = new_header;
	 }
};
struct DataFieldSettings_compareIndex {
	bool operator() (DataFieldSettings* obj1, DataFieldSettings* obj2) {
		if ( obj1 == NULL ) return true;
		if ( obj2 == NULL ) return false;
		return (obj1->index < obj2->index);
	}
 };

/**
 * @class   wosh::IDataFieldWrapper
 * @brief   Wrapper degigned to extract a filed using a function pointer.
 *          Functionoid, support regular function-pointer (as functor)
 ****************************************************************************
 *
 * @ingroup DataModels
 ****************************************************************************
 * @version 0.8.384 $Id $
 * @author  Alessandro Polo
 ****************************************************************************/
template <class OBJECT_TYPE>
class IDataFieldWrapper
 {
	public:
		IDataFieldWrapper( const OBJECT_TYPE* obj = NULL ) : object(obj) { }
		virtual ~IDataFieldWrapper() { }

	public:
		virtual ISerializable* extract( OBJECT_TYPE* object ) const = 0;
	public:
		DataFieldSettings info;
	public:
		inline ISerializable* operator()() { return extract(this->object); }
		inline ISerializable* operator()( OBJECT_TYPE* obj ) { return extract(obj); }
	protected:
		const OBJECT_TYPE* object;
 };

///----------------------------------------------------------------------------------------------------------------------
/**
 * @class   wosh::DataFieldWrapperT
 * @brief   IDataFieldWrapper template for generic (direct) getters.
 ****************************************************************************
 *
 * @ingroup DataModels
 ****************************************************************************
 * @version 0.8.384 $Id $
 * @author  Alessandro Polo
 ****************************************************************************/
template <class OBJECT_TYPE, typename RETURN_TYPE, class ALLOCATOR_TYPE>
class DataFieldWrapperT : public IDataFieldWrapper<OBJECT_TYPE>
 {
	public:
		typedef RETURN_TYPE (OBJECT_TYPE::*FieldExtractor)(void) const;
	public:
		explicit DataFieldWrapperT( FieldExtractor fptr ) 
			: IDataFieldWrapper<OBJECT_TYPE>(), fieldExtractorPtr(fptr) { }
		explicit DataFieldWrapperT( FieldExtractor fptr, const Variant& optHeader = Variant::EmptyVariant, int default_index = -1 ) 
			: IDataFieldWrapper<OBJECT_TYPE>(), fieldExtractorPtr(fptr) {
			this->info.setHeader( optHeader.clone() );
			this->info.index = default_index;
		 }
	public:
		inline ISerializable* extract( OBJECT_TYPE* object ) const {
			return new ALLOCATOR_TYPE( (object->*fieldExtractorPtr)() );
		 }
	protected:
		FieldExtractor fieldExtractorPtr;
};

///----------------------------------------------------------------------------------------------------------------------

template <class OBJECT_TYPE>
class DataFieldWrapperT<OBJECT_TYPE, ISerializable*, void> : public IDataFieldWrapper<OBJECT_TYPE>
 {
	public:
		typedef ISerializable* (OBJECT_TYPE::*FieldExtractor)(void) const;
	public:
		explicit DataFieldWrapperT( FieldExtractor fptr ) 
			: IDataFieldWrapper<OBJECT_TYPE>(), fieldExtractorPtr(fptr) { }
		explicit DataFieldWrapperT( FieldExtractor fptr, const Variant& optHeader = Variant::EmptyVariant, int default_index = -1 ) 
			: IDataFieldWrapper<OBJECT_TYPE>(), fieldExtractorPtr(fptr) {
			this->info.setHeader( optHeader.clone() );
			this->info.index = default_index;
		 }
	public:
		inline ISerializable* extract( OBJECT_TYPE* object ) const {
			return (object->*fieldExtractorPtr)();
		 }
	protected:
		FieldExtractor fieldExtractorPtr;
};

///----------------------------------------------------------------------------------------------------------------------
/**
 * @class   wosh::DataFieldSubWrapperT
 * @brief   IDataFieldWrapper template for indirect getters [object->get1()->get2()].
 ****************************************************************************
 *
 * @ingroup DataModels
 ****************************************************************************
 * @version 0.8.384 $Id $
 * @author  Alessandro Polo
 ****************************************************************************/
template <class OBJECT_TYPE, class PROXY_TYPE, typename RETURN_TYPE, class ALLOCATOR_TYPE>
class DataFieldSubWrapperT : public IDataFieldWrapper<OBJECT_TYPE>
 {
	public:
		DataFieldSubWrapperT() { }
};
// specialization for PROXY_TYPE references (they should be const! this won't free anything!)
template <class OBJECT_TYPE, class PROXY_TYPE, typename RETURN_TYPE, class ALLOCATOR_TYPE>
class DataFieldSubWrapperT<OBJECT_TYPE, PROXY_TYPE&, RETURN_TYPE, ALLOCATOR_TYPE> : public IDataFieldWrapper<OBJECT_TYPE>
 {
	public:
		typedef PROXY_TYPE& (OBJECT_TYPE::*ProxyExtractor)(void) const;
		typedef RETURN_TYPE (PROXY_TYPE::*FieldExtractor)(void) const;
	public:
		explicit DataFieldSubWrapperT<OBJECT_TYPE, PROXY_TYPE&, RETURN_TYPE, ALLOCATOR_TYPE>( ProxyExtractor proxy_fptr, FieldExtractor field_fptr ) 
			: IDataFieldWrapper<OBJECT_TYPE>(), proxyExtractorPtr(proxy_fptr), fieldExtractorPtr(field_fptr) { }
		explicit DataFieldSubWrapperT<OBJECT_TYPE, PROXY_TYPE&, RETURN_TYPE, ALLOCATOR_TYPE>( ProxyExtractor proxy_fptr, FieldExtractor field_fptr, const Variant& optHeader = Variant::EmptyVariant, int default_index = -1 ) 
			: IDataFieldWrapper<OBJECT_TYPE>(), proxyExtractorPtr(proxy_fptr), fieldExtractorPtr(field_fptr) {
			this->info.setHeader( optHeader.clone() );
			this->info.index = default_index;
		 }
	public:
		inline ISerializable* extract( OBJECT_TYPE* object ) const {
			PROXY_TYPE& proxy = (object->*proxyExtractorPtr)();
			return new ALLOCATOR_TYPE( (proxy.*fieldExtractorPtr)() );
		 }
	protected:
		ProxyExtractor proxyExtractorPtr;
		FieldExtractor fieldExtractorPtr;
};
// specialization for PROXY_TYPE references (they should be const! this won't free anything!) AND RETURN_TYPE pointer (acquired, not copied by allocator)
template <class OBJECT_TYPE, class PROXY_TYPE, typename RETURN_TYPE>
class DataFieldSubWrapperT<OBJECT_TYPE, PROXY_TYPE&, RETURN_TYPE, void> : public IDataFieldWrapper<OBJECT_TYPE>
 {
	public:
		typedef PROXY_TYPE& (OBJECT_TYPE::*ProxyExtractor)(void) const;
		typedef RETURN_TYPE (PROXY_TYPE::*FieldExtractor)(void) const;
	public:
		explicit DataFieldSubWrapperT<OBJECT_TYPE, PROXY_TYPE&, RETURN_TYPE, void>( ProxyExtractor proxy_fptr, FieldExtractor field_fptr ) 
			: IDataFieldWrapper<OBJECT_TYPE>(), proxyExtractorPtr(proxy_fptr), fieldExtractorPtr(field_fptr) { }
		explicit DataFieldSubWrapperT<OBJECT_TYPE, PROXY_TYPE&, RETURN_TYPE, void>( ProxyExtractor proxy_fptr, FieldExtractor field_fptr, const Variant& optHeader = Variant::EmptyVariant, int default_index = -1 ) 
			: IDataFieldWrapper<OBJECT_TYPE>(), proxyExtractorPtr(proxy_fptr), fieldExtractorPtr(field_fptr) {
			this->info.setHeader( optHeader.clone() );
			this->info.index = default_index;
		 }
	public:
		inline ISerializable* extract( OBJECT_TYPE* object ) const {
			PROXY_TYPE& proxy = (object->*proxyExtractorPtr)();
			return (proxy.*fieldExtractorPtr)();
		 }
	protected:
		ProxyExtractor proxyExtractorPtr;
		FieldExtractor fieldExtractorPtr;
};
// specialization for PROXY_TYPE pointers (they should be const! this won't free anything!)
template <class OBJECT_TYPE, class PROXY_TYPE, typename RETURN_TYPE, class ALLOCATOR_TYPE>
class DataFieldSubWrapperT<OBJECT_TYPE, PROXY_TYPE*, RETURN_TYPE, ALLOCATOR_TYPE> : public IDataFieldWrapper<OBJECT_TYPE>
 {
	public:
		typedef PROXY_TYPE* (OBJECT_TYPE::*ProxyExtractor)(void) const;
		typedef RETURN_TYPE (PROXY_TYPE::*FieldExtractor)(void) const;
	public:
		DataFieldSubWrapperT<OBJECT_TYPE, PROXY_TYPE*, RETURN_TYPE, ALLOCATOR_TYPE>( ProxyExtractor proxy_fptr, FieldExtractor field_fptr ) 
			: IDataFieldWrapper<OBJECT_TYPE>(), proxyExtractorPtr(proxy_fptr), fieldExtractorPtr(field_fptr) { }
		DataFieldSubWrapperT<OBJECT_TYPE, PROXY_TYPE*, RETURN_TYPE, ALLOCATOR_TYPE>( ProxyExtractor proxy_fptr, FieldExtractor field_fptr, const Variant& optHeader = Variant::EmptyVariant, int default_index = -1 ) 
			: IDataFieldWrapper<OBJECT_TYPE>(), proxyExtractorPtr(proxy_fptr), fieldExtractorPtr(field_fptr) {
			this->info.setHeader( optHeader.clone() );
			this->info.index = default_index;
		 }
	public:
		inline ISerializable* extract( OBJECT_TYPE* object ) const {
			PROXY_TYPE* proxy = (object->*proxyExtractorPtr)();
			if ( proxy == NULL ) return NULL;
			return new ALLOCATOR_TYPE( (proxy->*fieldExtractorPtr)() );
		 }
	protected:
		ProxyExtractor proxyExtractorPtr;
		FieldExtractor fieldExtractorPtr;
};
// specialization for PROXY_TYPE pointers (they should be const! this won't free anything!) AND RETURN_TYPE pointer (acquired, not copied by allocator)
template <class OBJECT_TYPE, class PROXY_TYPE, typename RETURN_TYPE>
class DataFieldSubWrapperT<OBJECT_TYPE, PROXY_TYPE*, RETURN_TYPE*, void> : public IDataFieldWrapper<OBJECT_TYPE>
 {
	public:
		typedef PROXY_TYPE* (OBJECT_TYPE::*ProxyExtractor)(void) const;
		typedef RETURN_TYPE* (PROXY_TYPE::*FieldExtractor)(void) const;
	public:
		DataFieldSubWrapperT<OBJECT_TYPE, PROXY_TYPE*, RETURN_TYPE*, void>( ProxyExtractor proxy_fptr, FieldExtractor field_fptr ) 
			: IDataFieldWrapper<OBJECT_TYPE>(), proxyExtractorPtr(proxy_fptr), fieldExtractorPtr(field_fptr) { }
		DataFieldSubWrapperT<OBJECT_TYPE, PROXY_TYPE*, RETURN_TYPE*, void>( ProxyExtractor proxy_fptr, FieldExtractor field_fptr, const Variant& optHeader = Variant::EmptyVariant, int default_index = -1 ) 
			: IDataFieldWrapper<OBJECT_TYPE>(), proxyExtractorPtr(proxy_fptr), fieldExtractorPtr(field_fptr) {
			this->info.setHeader( optHeader.clone() );
			this->info.index = default_index;
		 }
	public:
		inline ISerializable* extract( OBJECT_TYPE* object ) const {
			PROXY_TYPE* proxy = (object->*proxyExtractorPtr)();
			if ( proxy == NULL ) return NULL;
			return (proxy->*fieldExtractorPtr)();
		 }
	protected:
		ProxyExtractor proxyExtractorPtr;
		FieldExtractor fieldExtractorPtr;
};

///----------------------------------------------------------------------------------------------------------------------
///----------------------------------------------------------------------------------------------------------------------
/**
 * @class   wosh::IDataAdapter
 * @brief   Generic Data Adapter (pure abstract) interface.
 *          Provides an interface for accessing a custom set of data.
 ****************************************************************************
 *
 * @ingroup DataModels
 ****************************************************************************
 * @version 0.8.384 $Id $
 * @author  Alessandro Polo
 ****************************************************************************/
class IDataAdapter
 {
	public:
		virtual void transactionBeginRead() const = 0;
		virtual void transactionBeginWrite() const = 0;
		virtual void transactionEnd() const = 0;

		virtual unsigned int loadItems() = 0;

		virtual unsigned int getItemsCount() const = 0;

	public:
		virtual ~IDataAdapter() { }
 };
/**
 * @class   wosh::DataAdapter
 * @brief   IDataAdapter template for a generic (item) class.
 ****************************************************************************
 *
 * @ingroup DataModels
 ****************************************************************************
 * @version 0.8.384 $Id $
 * @author  Alessandro Polo
 ****************************************************************************/
template <class OBJECT_TYPE>
class DataAdapter : public IDataAdapter
 {
	public:
		typedef std::vector<OBJECT_TYPE*> tObjectVector;

	public:
		inline OBJECT_TYPE* getItem( unsigned int index ) {
			if ( index >= this->items.size() ) return NULL;
			return this->items.at(index);
		 }
		inline const OBJECT_TYPE* getItem( unsigned int index ) const {
			if ( index >= this->items.size() ) return NULL;
			return this->items.at(index);
		 }

//		const tObjectVector& getItems()	const		{ return this->items; }
		inline tObjectVector& getItems()			{ return this->items; }

		inline unsigned int getItemsCount() const	{ return this->items.size(); }

	protected:
		tObjectVector items;
 };



///----------------------------------------------------------------------------------------------------------------------
/**
 * @class   wosh::DataAdapterArray
 * @brief   DataAdapter template designed for standard array container.
 ****************************************************************************
 *
 * @ingroup DataModels
 ****************************************************************************
 * @version 0.8.384 $Id $
 * @author  Alessandro Polo
 ****************************************************************************/
template <class OBJECT_TYPE>
class DataAdapterItem: public DataAdapter<OBJECT_TYPE>
 {
	public:
		DataAdapterItem( OBJECT_TYPE* obj_item ) : object(obj_item) { }
	public:
		inline void transactionBeginRead() const	{ }
		inline void transactionBeginWrite() const	{ }
		inline void transactionEnd() const			{ }

		unsigned int loadItems() {
			this->items.clear();
			if ( this->object == NULL ) return 0;
			this->items.push_back( this->object );
			return 1;
		 }

	protected:
		OBJECT_TYPE* object;
};

///----------------------------------------------------------------------------------------------------------------------
/**
 * @class   wosh::DataAdapterArray
 * @brief   DataAdapter template designed for standard array container.
 ****************************************************************************
 *
 * @ingroup DataModels
 ****************************************************************************
 * @version 0.8.384 $Id $
 * @author  Alessandro Polo
 ****************************************************************************/
template <class OBJECT_TYPE>
class DataAdapterArray: public DataAdapter<OBJECT_TYPE>
 {
	public:
		DataAdapterArray( OBJECT_TYPE** list, unsigned int number ) : dataset(list), count(number) { } // copy container reference
	public:
		inline void transactionBeginRead() const	{ }
		inline void transactionBeginWrite() const	{ }
		inline void transactionEnd() const		{ }

		unsigned int loadItems() {
			this->items.clear();
			if ( this->dataset == NULL ) return 0;
			for ( unsigned int i=0; i<count; ++i ) {
				if ( this->dataset[i] == NULL ) continue;
				this->items.push_back( this->dataset[i] );
			 }
			return this->items.size();
		 }

	protected:
		OBJECT_TYPE** dataset;
		unsigned int count;
};


///----------------------------------------------------------------------------------------------------------------------
/**
 * @class   wosh::DataAdapterListT
 * @brief   DataAdapter template designed for wosh::ListT container.
 ****************************************************************************
 *
 * @ingroup DataModels
 ****************************************************************************
 * @version 0.8.384 $Id $
 * @author  Alessandro Polo
 ****************************************************************************/
template <class OBJECT_TYPE>
class DataAdapterListT: public DataAdapter<OBJECT_TYPE>
 {
	public:
		DataAdapterListT( const wosh::ListT<OBJECT_TYPE*>& list ) : dataset(list) { } // copy container reference
	public:
		inline void transactionBeginRead() const	{ this->dataset.transactionBeginRead(); }
		inline void transactionBeginWrite() const	{ this->dataset.transactionBeginWrite(); }
		inline void transactionEnd() const			{ this->dataset.transactionEnd(); }

		unsigned int loadItems() {
			this->items.clear();
			typename wosh::ListT<OBJECT_TYPE*>::ConstIterator it_o;
			const typename wosh::ListT<OBJECT_TYPE*>::ConstIterator it_o_end = this->dataset.end();
			for ( it_o=this->dataset.begin(); it_o!=it_o_end; ++it_o) {
				if ( *it_o == NULL ) continue;
				this->items.push_back(*it_o);
			 }
			return this->items.size();
		 }

	protected:
		const typename wosh::ListT<OBJECT_TYPE*>& dataset;
};

/**
 * @class   wosh::DataAdapterMapT
 * @brief   DataAdapter template designed for wosh::MapT container.
 ****************************************************************************
 *
 * @ingroup DataModels
 ****************************************************************************
 * @version 0.8.384 $Id $
 * @author  Alessandro Polo
 ****************************************************************************/
template <typename MAP_KEY_TYPE, class OBJECT_TYPE>
class DataAdapterMapT: public DataAdapter<OBJECT_TYPE>
 {
	public:
		DataAdapterMapT( const wosh::MapT<MAP_KEY_TYPE, OBJECT_TYPE*>& map ) : dataset(map) { } // copy container reference
	public:
		inline void transactionBeginRead() const	{ this->dataset.transactionBeginRead(); }
		inline void transactionBeginWrite() const	{ this->dataset.transactionBeginWrite(); }
		inline void transactionEnd() const			{ this->dataset.transactionEnd(); }

		unsigned int loadItems() {
			this->items.clear();
			typename wosh::MapT<MAP_KEY_TYPE, OBJECT_TYPE*>::ConstIterator it_o;
			const typename wosh::MapT<MAP_KEY_TYPE, OBJECT_TYPE*>::ConstIterator it_o_end = this->dataset.end();
			for ( it_o=this->dataset.begin(); it_o!=it_o_end; ++it_o) {
				if ( it_o->second == NULL ) continue;
				this->items.push_back(it_o->second);
			 }
			return this->items.size();
		 }

	protected:
		const typename wosh::MapT<MAP_KEY_TYPE, OBJECT_TYPE*>& dataset;
};

///----------------------------------------------------------------------------------------------------------------------
///----------------------------------------------------------------------------------------------------------------------
/**
 * @class   wosh::IDataFieldCollector
 * @brief   Generic Collector of DataFields (pure abstract) interface.
 *          Get fields from default set.
 ****************************************************************************
 *
 * @ingroup DataModels
 ****************************************************************************
 * @version 0.8.384 $Id $
 * @author  Alessandro Polo
 ****************************************************************************/
class IDataFieldCollector
 {
	public:
		virtual int getFields( std::vector<DataFieldSettings*>& output_fields, short visible_pattern ) const = 0;

		virtual const std::string& getDataSetName() const = 0;

	public:
		inline int getDefaults( std::vector<DataFieldSettings*>& output_fields ) const {
			return getFields(output_fields, 1);
		 }
		inline int getAll( std::vector<DataFieldSettings*>& output_fields ) const {
			return getFields(output_fields, 0);
		 }
		void fixFields( std::vector<DataFieldSettings*>& fields ) const {
			int cIndex = -1;
			std::vector<DataFieldSettings*>::iterator it_f;
			for ( it_f=fields.begin(); it_f!=fields.end(); ) {
				if ( *it_f == NULL ) {
					it_f = fields.erase(it_f);
					continue;
				 }
				if ( (*it_f)->index == cIndex )
					++(*it_f)->index;
				++cIndex;
				++it_f;
			 }
		 }

	public:
		virtual ~IDataFieldCollector() { }
 };

/**
 * @class   wosh::DataFieldCollector
 * @brief   Generic Data Extractor (pure abstract) interface.
 *          Extract fields of items from a generic DataAdapter
 ****************************************************************************
 *
 * @ingroup DataModels
 ****************************************************************************
 * @version 0.8.384 $Id $
 * @author  Alessandro Polo
 ****************************************************************************/
template <class OBJECT_TYPE>
class DataFieldCollector : public IDataFieldCollector
 {
	public:
		typedef IDataFieldWrapper<OBJECT_TYPE> tDataFieldWrapper;
	public:
		DataFieldCollector() : IDataFieldCollector() { }

	public:
		void add( tDataFieldWrapper* dfw ) {
			if ( dfw == NULL ) return;
			dfw->info.uid = this->fields.size();
			this->fields.push_back(dfw);
		 }

		template <typename RETURN_TYPE, class ALLOCATOR_TYPE>
		void add( typename DataFieldWrapperT<OBJECT_TYPE, RETURN_TYPE, ALLOCATOR_TYPE>::FieldExtractor fptr,
					const Variant& header, int default_index, bool default_visible = true ) {
			DataFieldWrapperT<OBJECT_TYPE, RETURN_TYPE, ALLOCATOR_TYPE>* dfw;
			dfw = new DataFieldWrapperT<OBJECT_TYPE, RETURN_TYPE, ALLOCATOR_TYPE>(fptr, header, default_index);
			dfw->info.uid = this->fields.size();
			dfw->info.visible = default_visible;
			this->fields.push_back( dfw );
		 }

		inline void setDataSetName( const std::string& name )	{ this->datasetName = name; }

	public:
		int getFields( std::vector<DataFieldSettings*>& output_fields, short visible_pattern ) const {
			typename std::vector<tDataFieldWrapper*>::const_iterator it_f;
			const typename std::vector<tDataFieldWrapper*>::const_iterator it_f_end = this->fields.end();
			for ( it_f=this->fields.begin(); it_f!=it_f_end; ++it_f ) {
				if ( *it_f == NULL ) continue;
				if ( visible_pattern != 0 ) {
					if ( visible_pattern == 1 && !(*it_f)->info.visible ) continue;
					if ( visible_pattern == 2 && (*it_f)->info.visible ) continue;
				 }
				output_fields.push_back( &(*it_f)->info );
			 }
			// sort by index
			std::sort(output_fields.begin(), output_fields.end(), DataFieldSettings_compareIndex() );
			fixFields(output_fields);
			return output_fields.size();
		 }
		inline const std::string& getDataSetName() const		{ return this->datasetName; }

	public:

		tDataFieldWrapper* getDataFieldWrapperByUID( int uid ) const {
			typename std::vector<tDataFieldWrapper*>::const_iterator it_f;
			const typename std::vector<tDataFieldWrapper*>::const_iterator it_f_end = this->fields.end();
			for ( it_f=this->fields.begin(); it_f!=it_f_end; ++it_f ) {
				if ( *it_f == NULL ) continue;
				if ( (*it_f)->info.uid != uid ) continue;
				return *it_f;
			 }
			return NULL;
		 }

	protected:
		std::vector<tDataFieldWrapper*> fields;
		std::string datasetName;
};

///----------------------------------------------------------------------------------------------------------------------
///----------------------------------------------------------------------------------------------------------------------
/**
 * @class   wosh::IDataFieldExtractor
 * @brief   Generic Data Extractor (pure abstract) interface.
 *          Extract fields of items from a generic DataAdapter
 ****************************************************************************
 *
 * @ingroup DataModels
 ****************************************************************************
 * @version 0.8.384 $Id $
 * @author  Alessandro Polo
 ****************************************************************************/
class IDataFieldExtractor
 {
	public:
		virtual ISerializable* extract( unsigned int item_index, int wrapper_uid ) = 0;

		virtual IDataAdapter* getDataAdapter() = 0;
		virtual IDataFieldCollector* getDataFieldCollector() = 0;

	public:
		virtual ~IDataFieldExtractor() { }
 };

///----------------------------------------------------------------------------------------------------------------------
/**
 * @class   wosh::DataFieldExtractor
 * @brief   IDataFieldExtractor template for a generic (item) class.
 ****************************************************************************
 *
 * @ingroup DataModels
 ****************************************************************************
 * @version 0.8.384 $Id $
 * @author  Alessandro Polo
 ****************************************************************************/
template <class OBJECT_TYPE>
class DataFieldExtractor : public IDataFieldExtractor
 {
	public:
		DataFieldExtractor( DataAdapter<OBJECT_TYPE>* data_adapter, DataFieldCollector<OBJECT_TYPE>* collector_fields )
			: adapter(data_adapter), fields(collector_fields) {
		 }
		virtual ~DataFieldExtractor() { }

	public:
		ISerializable* extract( unsigned int item_index, int wrapper_uid ) {
			if ( this->fields == NULL ) return NULL;
			if ( this->adapter == NULL ) return NULL;
			typename DataFieldCollector<OBJECT_TYPE>::tDataFieldWrapper* dfw = this->fields->getDataFieldWrapperByUID(wrapper_uid);
			if ( dfw == NULL ) return NULL;
			//return dfw->extract();
			OBJECT_TYPE* obj = this->adapter->getItem(item_index);
			if ( obj == NULL ) return NULL;
			return dfw->extract(obj);
		 }

		inline IDataAdapter* getDataAdapter()					{ return this->adapter; }
		inline IDataFieldCollector* getDataFieldCollector()		{ return this->fields; }


	 public:
		template<class CONTAINER_TYPE>
		static DataFieldExtractor<OBJECT_TYPE>* createFor( const CONTAINER_TYPE& container, const std::string& dataset_name ) {
			CONTAINER_TYPE* dataAdapter = new CONTAINER_TYPE(container);
			DataFieldCollector<OBJECT_TYPE>* dataFields = OBJECT_TYPE::getDataFields();
			DataFieldExtractor<OBJECT_TYPE>* dataExtractor = new DataFieldExtractor<OBJECT_TYPE>(dataAdapter, dataFields);
			dataFields->setDataSetName(dataset_name);
			return dataExtractor;
		 }

	protected:
		DataAdapter<OBJECT_TYPE>* adapter;
		DataFieldCollector<OBJECT_TYPE>* fields;
};

///----------------------------------------------------------------------------------------------------------------------
///----------------------------------------------------------------------------------------------------------------------
/**
 * @class   wosh::IDataFieldExtractor
 * @brief   Generic Data Extractor (pure abstract) interface.
 *          Extract fields of items from a generic DataAdapter
 ****************************************************************************
 *
 * @ingroup DataModels
 ****************************************************************************
 * @version 0.8.384 $Id $
 * @author  Alessandro Polo
 ****************************************************************************/
class IItemExtractor
 {
	public:
		virtual ISerializable* extract( unsigned int item_index ) = 0;

		virtual IDataAdapter* getDataAdapter() = 0;

		virtual int loadItems() = 0;

		virtual void setPrimaryKeyValue( const ISerializable* compare_data ) {
			this->primary_key_value = compare_data;
		 }

	public:
		IItemExtractor()
			: primary_key_value(NULL){ }
		virtual ~IItemExtractor() { }

	protected:
		const ISerializable* primary_key_value;
 };

///----------------------------------------------------------------------------------------------------------------------
///----------------------------------------------------------------------------------------------------------------------
/**
 * @class   wosh::ObjectExtractor
 * @brief   todo
 ****************************************************************************
 *
 * @ingroup DataModels
 ****************************************************************************
 * @version 0.8.439 $Id $
 * @author  Alessandro Polo
 ****************************************************************************/
template <class OBJECT_TYPE, typename PRIMARY_KEY_TYPE>
class ObjectExtractor : public IItemExtractor
 {
	public:
		typedef PRIMARY_KEY_TYPE (OBJECT_TYPE::*PrimaryKeyExtractor)(void) const;

	public:
		ObjectExtractor( DataAdapter<OBJECT_TYPE>* data_adapter )
			: IItemExtractor(), adapter(data_adapter), primaryKeyExtractorPtr(NULL) {
		 }
		virtual ~ObjectExtractor() {
			setPrimaryKeyValue(NULL);
		 }

	public:
		virtual ISerializable* extract( unsigned int item_index ) {
			return this->adapter->getItem(item_index);
		 }

	public:
		inline IDataAdapter* getDataAdapter()				{ return this->adapter; }


	public:
		void setPrimaryKeyExtractor( PrimaryKeyExtractor fptr ) {
			this->primaryKeyExtractorPtr = fptr;
		 }

	public:

		int loadItems() {
			if ( this->adapter == NULL ) return -1;
			int count = this->adapter->loadItems();
			if ( this->primary_key_value == NULL )
				return count;
			const Variant* pkvVar = NULL;
			if ( this->primary_key_value->isClass(Variant::className()) ) {
				pkvVar = dynamic_cast<const wosh::Variant*>(this->primary_key_value);
			 }
			if ( pkvVar == NULL )
				return count;
			typename DataAdapter<OBJECT_TYPE>::tObjectVector::iterator it;
			for ( it=this->adapter->getItems().begin(); it!=this->adapter->getItems().end(); ) {
				if ( *it == NULL ) { ++it; continue; }
				if ( pkvVar == NULL ) { ++it; continue; }
				if ( *pkvVar != ((*it)->*primaryKeyExtractorPtr)() ) // Variant implements comparison op with default types
					it = this->adapter->getItems().erase(it);
				else
					++it;
			 }
			return this->adapter->getItems().size();
		 }


	 public:
		template<class CONTAINER_TYPE>
		static ObjectExtractor<OBJECT_TYPE, PRIMARY_KEY_TYPE>* createFor( const CONTAINER_TYPE& container, PrimaryKeyExtractor fptr ) {
			CONTAINER_TYPE* dataAdapter = new CONTAINER_TYPE(container);
			ObjectExtractor<OBJECT_TYPE, PRIMARY_KEY_TYPE>* objExtractor = new ObjectExtractor<OBJECT_TYPE, PRIMARY_KEY_TYPE>(dataAdapter);
			objExtractor->setPrimaryKeyExtractor(fptr);
			return objExtractor;
		 }

	protected:
		DataAdapter<OBJECT_TYPE>* adapter;
		PrimaryKeyExtractor primaryKeyExtractorPtr;

};


///----------------------------------------------------------------------------------------------------------------------
///----------------------------------------------------------------------------------------------------------------------
/**
 * @class   wosh::IDataFieldRenderer
 * @brief   Generic Data Renderer (pure abstract) interface.
 ****************************************************************************
 *
 * @ingroup DataModels
 ****************************************************************************
 * @version 0.8.384 $Id $
 * @author  Alessandro Polo
 ****************************************************************************/
class IDataRenderer
 {
	public:
		IDataRenderer()
			: page_startIndex(0), page_endIndex(-1) { }
		virtual ~IDataRenderer() { }

	public:
		virtual ISerializable* create() = 0;

	public:
		inline void setPageStart( long start )				{ this->page_startIndex = start; }
		inline void setPageEnd( long end )					{ this->page_endIndex = end; }
		inline void setPage( long start, long end = -1 )	{ this->page_startIndex = start; this->page_endIndex = end; }

		inline long getPageStart() const					{ return this->page_startIndex; }
		inline long getPageEnd() const						{ return this->page_endIndex; }

	protected:
		long page_startIndex;
		long page_endIndex;

 };

///----------------------------------------------------------------------------------------------------------------------
///----------------------------------------------------------------------------------------------------------------------
/**
 * @class   wosh::IDataFieldRenderer
 * @brief   Generic Data Renderer (pure abstract) interface.
 ****************************************************************************
 *
 * @ingroup DataModels
 ****************************************************************************
 * @version 0.8.384 $Id $
 * @author  Alessandro Polo
 ****************************************************************************/
class IDataFieldRenderer : public IDataRenderer
 {
	public:
		IDataFieldRenderer()
			: IDataRenderer() { }
		virtual ~IDataFieldRenderer() { }

	public:
		virtual std::vector<DataFieldSettings*>& getFields() = 0;

		virtual WRESULT renderFieldHeader() = 0;

 };

///----------------------------------------------------------------------------------------------------------------------
///----------------------------------------------------------------------------------------------------------------------
/**
 * @class   wosh::TableRenderer
 * @brief   wosh::IDataFieldRenderer implementation which generates wosh::Table output.
 ****************************************************************************
 *
 * @ingroup DataModels
 ****************************************************************************
 * @version 0.8.384 $Id $
 * @author  Alessandro Polo
 ****************************************************************************/
class TableRenderer : public IDataFieldRenderer
 {
	public:
		enum HEADER_MODE {
			HEADER_NONE				= 0x00,
			HEADER_HORIZONTAL		= 0x01,
			HEADER_VERTICAL			= 0x02
		 };
		enum ORIENTATION {
			ORIENTATION_VERTICAL	= 0x00,
			ORIENTATION_HORIZONTAL	= 0x01,
		 };

	public:
		TableRenderer( IDataFieldExtractor* data_extractor )
			: extractor(data_extractor),
			render_header(HEADER_HORIZONTAL), orientation(ORIENTATION_VERTICAL),
			outputTbl(NULL) {
		 }
		virtual ~TableRenderer() { }

	public:
		inline short getHeaderMode() const						{ return this->render_header; }
		inline ORIENTATION getOrientation() const				{ return this->orientation; }

		inline void setHeaderMode( short mode )					{ this->render_header = mode; }
		inline void setOrientation( ORIENTATION item_dir )		{ this->orientation = item_dir; }

		inline std::vector<DataFieldSettings*>& getFields()		{ return this->fields; }

	public:

		WRESULT feed_( Table* table, long startIndex, long endIndex ) {
			if ( table == NULL ) return WRET_ERR_PARAM;
			if ( this->extractor == NULL ) return WRET_ERR_ILLEGAL_USE;
			if ( this->extractor->getDataAdapter() == NULL ) return WRET_ERR_ILLEGAL_USE;
			if ( this->fields.size() == 0 ) return WRET_ERR_ILLEGAL_USE;
			if ( startIndex < 0 ) startIndex = 0;
			if ( endIndex <= -1 ) endIndex = this->extractor->getDataAdapter()->getItemsCount();
			table->alloc( endIndex - startIndex, this->fields.size() );
			unsigned int iRow = 0;
			std::vector<DataFieldSettings*>::const_iterator it_f;
			const std::vector<DataFieldSettings*>::const_iterator it_f_end = this->fields.end();
			for ( unsigned int iItem=startIndex; (int)iItem<endIndex; ++iItem ) { 
				for ( it_f=this->fields.begin(); it_f!=it_f_end; ++it_f ) {
					if ( *it_f == NULL ) continue;
					ISerializable* cObj = this->extractor->extract( iItem, (*it_f)->uid );
					table->set( cObj, iRow, (*it_f )->index );
				 }
				++iRow;
			 }
			return WRET_OK;
		 }

	public:
		Table* create() {
			if ( this->extractor == NULL ) return NULL;
			if ( this->extractor->getDataAdapter() == NULL ) return NULL;
			if ( this->fields.size() == 0 ) return NULL;
			this->extractor->getDataAdapter()->transactionBeginRead();
			this->extractor->getDataAdapter()->loadItems();

			if ( this->outputTbl != NULL )
				delete this->outputTbl;
			this->outputTbl = new Table();
			if ( this->extractor->getDataFieldCollector() != NULL )
				this->outputTbl->setTableName( this->extractor->getDataFieldCollector()->getDataSetName() );
			feed_(this->outputTbl, this->page_startIndex, this->page_endIndex);
			this->extractor->getDataAdapter()->transactionEnd();
			renderFieldHeader();

			return this->outputTbl;
		 }

		WRESULT renderFieldHeader() {
			if ( this->render_header == (short)HEADER_NONE ) return WRET_ERR_PARAM;
			if ( this->outputTbl == NULL ) return WRET_ERR_ILLEGAL_USE;
			if ( this->render_header & (short)HEADER_HORIZONTAL ) {
				if ( !this->outputTbl->hasHeaderHorizontal() )
					this->outputTbl->allocHeaderHorizontal(true);
				std::vector<DataFieldSettings*>::const_iterator it_f;
				const std::vector<DataFieldSettings*>::const_iterator it_f_end = this->fields.end();
				for ( it_f=this->fields.begin(); it_f!=it_f_end; ++it_f ) {
					if ( *it_f == NULL ) continue;
					if ( (*it_f )->header == NULL ) continue;
					this->outputTbl->setHeaderHorizontal( (*it_f )->header->clone(), (*it_f )->index );
				 }
			 }
			if ( this->render_header & (short)HEADER_VERTICAL ) {
				if ( !this->outputTbl->hasHeaderVertical() )
					this->outputTbl->allocHeaderVertical(true);
				std::vector<DataFieldSettings*>::const_iterator it_f;
				const std::vector<DataFieldSettings*>::const_iterator it_f_end = this->fields.end();
				for ( it_f=this->fields.begin(); it_f!=it_f_end; ++it_f ) {
					if ( *it_f == NULL ) continue;
					if ( (*it_f )->header == NULL ) continue;
					this->outputTbl->setHeaderVertical( (*it_f )->header->clone(), (*it_f )->index );
				 }
			 }
			return WRET_OK;
		 }

	protected:
		IDataFieldExtractor* extractor;
		short render_header;
		ORIENTATION orientation;
		std::vector<DataFieldSettings*> fields;

		Table* outputTbl;
 };

///----------------------------------------------------------------------------------------------------------------------
///----------------------------------------------------------------------------------------------------------------------
/**
 * @class   wosh::ListRenderer
 * @brief   
 ****************************************************************************
 *
 * @ingroup DataModels
 ****************************************************************************
 * @version 0.8.384 $Id $
 * @author  Alessandro Polo
 ****************************************************************************/
class ListRenderer : public IDataRenderer
 {
	public:

	public:
		ListRenderer( IItemExtractor* data_extractor )
			: IDataRenderer(), extractor(data_extractor),
			outputList(NULL) {
		 }
		virtual ~ListRenderer() { }

	public:
		WRESULT setPrimaryKeyValue( const ISerializable* compare_data ) {
			if ( this->extractor == NULL ) return WRET_ERR_INTERNAL;
			this->extractor->setPrimaryKeyValue( compare_data );
			return WRET_OK;
		 }


		WRESULT feed_( List* list, long startIndex, long endIndex ) {
			if ( list == NULL ) return WRET_ERR_PARAM;
			if ( this->extractor == NULL ) return WRET_ERR_ILLEGAL_USE;
			if ( this->extractor->getDataAdapter() == NULL ) return WRET_ERR_ILLEGAL_USE;
			if ( startIndex < 0 ) startIndex = 0;
			if ( endIndex <= -1 ) endIndex = this->extractor->getDataAdapter()->getItemsCount();
			// render ITEMS!
			// foeach item
			//  
			for ( unsigned int iRow=startIndex; (int)iRow<endIndex; ++iRow ) { 
				ISerializable* cObj = this->extractor->extract( iRow );
				if ( cObj == NULL )
					list->push_back(NULL);
				else
					list->push_back( cObj->clone() );
			 }
			return WRET_OK;
		 }

	public:
		List* create() {
			if ( this->extractor == NULL ) return NULL;
			if ( this->extractor->getDataAdapter() == NULL ) return NULL;
			this->extractor->getDataAdapter()->transactionBeginRead();
			this->extractor->loadItems();

			if ( this->outputList != NULL )
				delete this->outputList;
			this->outputList = new List( this->extractor->getDataAdapter()->getItemsCount() );
			feed_(this->outputList, this->page_startIndex, this->page_endIndex);
			this->extractor->getDataAdapter()->transactionEnd();
			return this->outputList;
		 }

	protected:
		IItemExtractor* extractor;

		List* outputList;
 };

///----------------------------------------------------------------------------------------------------------------------
///----------------------------------------------------------------------------------------------------------------------



}; // namespace wosh

#endif //__WOSH_Core_DataModels_H__
